﻿#include"unrealircd.h"


/**
 * 
 * 这个模块主要是用于libcurl进行邮件的发送
 * 
 **/
#define STMP_HEAD_LENGTH 300
static CURLM *cm;
int maxStmpConnect = 20;//最大请求连接
int stmpConnect_cnt = 0;
SmtpList stmp_list_ready;
SmtpList stmp_list_process;
char *stmpUrl;
char *stmpUserName;
char *stmpUserPassWord;
char *stmpFrom;

void init_smtp(){
    stmpConnect_cnt = 0;
    stmpUrl=NULL;
    stmpUserName=NULL;
    stmpUserPassWord=NULL;
    stmpFrom=NULL;
    init_SmtpList(&stmp_list_ready);
    init_SmtpList(&stmp_list_process);
    cm = curl_multi_init();
    if(!cm){
        cm = NULL;
        return;
    }
    curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, (long)maxStmpConnect);

}

void init_SmtpList(SmtpList *list) {
	list->head.pre = NULL;
	list->head.next = &(list->end);
	list->end.pre = &(list->head);
	list->end.next = NULL;
	list->head.data = NULL;
	list->end.data = NULL;
}

static size_t smtp_writefunc(char *ptr, size_t size, size_t nmemb, SmtpData *userp)
{
	const char *data;
	size_t room = size * nmemb;

	if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
		return 0;
	}

	data = &(userp->sendData[userp->bytes_read]);

	if (data) {
		size_t len = strlen(data);
		if (room < len)
			len = room;
		memcpy(ptr, data, len);
		userp->bytes_read += len;

		return len;
	}

	return 0;
}

SmtpData * createSmtpData(char *data,char *toEmail){
    SmtpData* stmpdata=safe_alloc(sizeof(SmtpData));
    stmpdata->bytes_read=0;
    stmpdata->sendData=NULL;
	stmpdata->content=NULL;
    safe_strdup(stmpdata->content,data);
    stmpdata->tolist=NULL;
    stmpdata->tolist=curl_slist_append(stmpdata->tolist, toEmail);
    stmpdata->eh=NULL;
	stmpdata->headlist=NULL;
    return stmpdata;
}


/*
添加一个stmp请求到链表中
*/
void add_smtpList(SmtpData *stmpData, SmtpList *list) {
	SmtpNode *Node = malloc(sizeof(SmtpNode));
	Node->data = stmpData;
	Node->pre = list->end.pre;
	Node->pre->next = Node;
	list->end.pre = Node;
	Node->next = &(list->end);
}

/*
添加数据到stmp_list_ready链表中
*/
void add_smtpReady(SmtpData *stmpData) {
	add_smtpList(stmpData, &stmp_list_ready);
}

/*
完成一个stmp请求，删除stmp请求节点
*/
void delet_smtpList(SmtpNode *node) {
	if (node->pre == NULL || node->next == NULL) {
		return;
	}
	node->pre->next = node->next;
	node->next->pre = node->pre;
	free(node);
}

/*
将节点转化位置
*/
void remove_smtpList(SmtpNode *node, SmtpList *destination) {
	if (node->pre == NULL || node->next == NULL) {
		return;
	}
	node->pre->next = node->next;
	node->next->pre = node->pre;

	node->pre = destination->end.pre;
	node->pre->next = node;
	destination->end.pre = node;
	node->next = &(destination->end);
}

/*
将未开始的请求加入到请求集中，如果stmp最大连接数不超过maxStmpConnect，则不加入
*/
void smtp_process() {
	for (; stmpConnect_cnt < maxStmpConnect; stmpConnect_cnt++) {
		if ((stmp_list_ready.head.next) == &(stmp_list_ready.end)) {
			break;
		}
		SmtpNode * node = stmp_list_ready.head.next;
		do_smtp(node->data);
		remove_smtpList(node, &stmp_list_process);
	}
	int running_handles = 0;
	curl_multi_perform(cm, &running_handles);
    
}

/*
执行一个stmp请求
*/
void do_smtp(SmtpData *stmpData){
    if(!stmpUrl){
        stmpUrl=queryImConfigureValue("STMP_URL");
    }
    if(!stmpUrl)return;
    if(!stmpUserName){
        stmpUserName=queryImConfigureValue("STMP_USER_NAME");
    }
    if(!stmpUserName)return;
    if(!stmpUserPassWord){
        stmpUserPassWord=queryImConfigureValue("STMP_USER_PASSWORD");
    }
    if(!stmpUserPassWord)return;
    if(!stmpFrom){
        stmpFrom=queryImConfigureValue("STMP_FROM");
    }
    if(!stmpFrom)return;
    CURL *curl = curl_easy_init();
    if(curl){
		stmp_prepareSendData(stmpData);
        curl_easy_setopt(curl, CURLOPT_URL, stmpUrl);
        curl_easy_setopt(curl, CURLOPT_MAIL_FROM, stmpFrom);
        curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, stmpData->tolist);
        curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=LOGIN");
        curl_easy_setopt(curl, CURLOPT_USERNAME, stmpUserName);
		curl_easy_setopt(curl, CURLOPT_PASSWORD, stmpUserPassWord);
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, smtp_writefunc);
		curl_easy_setopt(curl, CURLOPT_READDATA, stmpData);
		stmpData->eh=curl;
        curl_multi_add_handle(cm, curl);

    }


}

SmtpNode *smtp_ListfindSmtpDataByCURL(CURL *eh,SmtpList *list){
    SmtpNode *node = list->head.next;
	while (node->next != NULL) {
		if (node->data->eh == eh) {
			return node;
		}
		node = node->next;
	}
	return NULL;
}

void SmtpNode_free(SmtpNode *node){
    SmtpData_free(node->data);
    delet_smtpList(node);
}

void SmtpData_free(SmtpData *data){
    curl_slist_free_all(data->tolist);
    curl_easy_cleanup(data->eh);
    safe_free(data->sendData);
	while(data->headlist){
		SmtpHeadList *temp=data->headlist->next;
		safe_free(data->headlist->headparme);
		safe_free(data->headlist->headvalue);
		safe_free(data->headlist);
		data->headlist=temp;
	}
	safe_free(data->content);
    safe_free(data);
}

void smtp_solve(){
    if (stmpConnect_cnt <= 0) {
		return;
	}
	int runing_handle = 0;
	CURLMcode fdset_code, timeout_code;
	fd_set R, W, E;
	long L;
	int M, Q;
	FD_ZERO(&R);
	FD_ZERO(&W);
	FD_ZERO(&E);
	if (fdset_code = curl_multi_fdset(cm, &R, &W, &E, &M)) {
		return;
	}
	struct timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 0;
	int num = select(M + 1, &R, &W, &E, &timeout);

    if (num != 0) {
		CURLMcode perform_code = curl_multi_perform(cm, &runing_handle);
		CURLMsg *msg;
		while ((msg = curl_multi_info_read(cm, &Q))) {
			if (msg->msg == CURLMSG_DONE) {
				CURL *e = msg->easy_handle;
				SmtpNode* node = smtp_ListfindSmtpDataByCURL(e,&stmp_list_process);
				ircd_log(LOG_ERROR,"stmp slove %s",node->data->sendData);
				curl_multi_remove_handle(cm, e);

				SmtpNode_free(node);
				stmpConnect_cnt--;
				smtp_process();
			}
		}
	}
	
}

/**
 * 构造发送信息
 */
void stmp_prepareSendData(SmtpData *stmpData){
	int len=STMP_HEAD_LENGTH+strlen(stmpData->content);
	char * temp=safe_alloc(len);
	SmtpHeadList *headlist=stmpData->headlist;
	int content_len=strlen(stmpData->content);
	int curr_len=0;
	while(headlist){
		char param[100]="";
		sprintf(param,"%s: %s\r\n",headlist->headparme,headlist->headvalue);
		int param_len=strlen(param);
		if(param_len+curr_len+content_len+1>len){
			char *temp1=safe_alloc(param_len+curr_len+1);
			temp1[0]='\0';
			strcat(temp1,temp);
			safe_free(temp);
			temp=temp1;
		}
		strcat(temp,param);
		curr_len+=param_len;
		headlist=headlist->next;
	}
	strcat(temp,stmpData->content);
	safe_strdup(stmpData->sendData,temp);
	safe_free(temp);
}

/**
 * 添加头部参数
 */
void stmp_addheadData(SmtpData *stmpData,char *param,char *value){
	SmtpHeadList *temp=safe_alloc(sizeof(SmtpHeadList));
	safe_strdup(temp->headparme,param);
	safe_strdup(temp->headvalue,value);
	temp->next=stmpData->headlist;
	stmpData->headlist=temp;
	return;
}